/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd.context.entity;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

import org.zhiqim.httpd.HttpEntity;
import org.zhiqim.httpd.HttpHeader;
import org.zhiqim.httpd.HttpSender;
import org.zhiqim.httpd.constants.HttpMimeType;
import org.zhiqim.httpd.context.ZmlContextConstants;
import org.zhiqim.httpd.context.core.Context;
import org.zhiqim.kernel.logging.Log;
import org.zhiqim.kernel.logging.LogFactory;
import org.zhiqim.kernel.model.codes.Base64;
import org.zhiqim.kernel.util.DateTimes;
import org.zhiqim.kernel.util.Files;
import org.zhiqim.kernel.util.Streams;
import org.zhiqim.kernel.util.Strings;
import org.zhiqim.kernel.util.Validates;

/**
 * 上传文件访问服务，用于固定访问地址为/service/upl/*，中间*=${fileDir}/${fileId}
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class UploadEntity implements HttpEntity, ZmlContextConstants
{
    private static final Log log = LogFactory.getLog(UploadEntity.class);
    
    @Override
    public boolean isMatch(String pathInContext)
    {
        return Validates.isMatch(pathInContext, _PATH_SERVICE_UPLOAD_ACCESS_);
    }
    
    @Override
    public void handle(HttpHeader header, HttpSender sender) throws IOException
    {
        Context context = (Context)header.getContext();
        String uploadRootDir = context.getServiceExecutor().getUploadService().getUploadRootDir();
        if (uploadRootDir == null)
        {
            log.error("[Upload][未配置上传根目录或上传根目录不允许访问][%s]", _SERV_UPLOAD_ROOT_DIR_);
            sender.sendError(_403_FORBIDDEN_);
            return;
        }
        
        String filePath = Strings.removeStartsWith(header.getPathInContext(), _PATH_UPLOAD_PREFIX_);
        String fileDir = Files.getFileDirPath(filePath, "/");
        String fileName = Files.getFileNameLinux(filePath);
        
        if (Validates.isNotEmpty(fileDir))
        {
            fileDir = Base64.decodeFileUrlUTF8(fileDir);
        }
        
        if (Validates.isEmpty(fileDir))
            filePath = uploadRootDir + fileName;
        else
            filePath = uploadRootDir + fileDir + "/" + fileName;
        
        File file = new File(filePath);
        if (!file.exists() || !file.isFile())
        {//不存在或不是文件
            sender.sendError(_404_NOT_FOUND_);
            return;
        }
        
        if (file.isHidden() || !file.canRead())
        {//隐藏、不可读和文件大小超限
            sender.sendError(_403_FORBIDDEN_);
            return;
        }
        
        //设置文件类型
        String fileExt = Files.getFileExt(fileName);
        sender.setContentType(HttpMimeType.getResourceMimeType(fileExt));
        
        long lastModified = file.lastModified();
        String lastModifiedTime = DateTimes.getDateTimeHttp(lastModified);
        String ifModifiedSince = header.getHeader(_IF_MODIFIED_SINCE_);
        if (ifModifiedSince != null && ifModifiedSince.indexOf(lastModifiedTime) != -1)
        {//时间相等
            sender.sendHeader(_304_NOT_MODIFIED_);
            return;
        }
        
        sender.setHeader(_ACCEPT_RANGES_, _BYTES_);
        sender.setHeader(_LAST_MODIFIED_, lastModifiedTime);
        
        if (header.isMethodResponseContent())
        {//GET,POST
            try(FileInputStream fis = new FileInputStream(file))
            {
                Streams.putBytes(fis, sender.getOutputStream());
            }
        }
        
        sender.commit();
    }
}
